/*
 Copyright 2008 Jason E. Smith Licensed under the Apache License, Version 2.0 (the "License");
 You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 */
new js.Class("js::Model", {
	traits : new Observer,
	
	preInitialize : function(json) {
		this.bind(arguments[0]);
		this.parent(arguments);
		return this;
	},
	
	extend : function(params){
		js.extend(this, params);
		this.fireEvent("modified", this);
		return this;
	},
	
	getModel : function() {
		var model = {}; 
		for(key in this) {
			if(typeof this[key] != "function") {
				model[key] = this[key];
			}
		}
		return model;
	},
	
	bind : function(obj) {
		if(!obj || (typeof obj !== "object"))  {
			throw new Error("Invalid args passed to js.Model. Expected a json/literal object.");
		}
		js.extend(this,obj);
		return this;
	},
	
    validate : function(log){
		var errors = JSONSchema.validate(this.getModel(),this.schema);
		if(errors.length) {
			var logerror = function(err){
				this.fireEvent("invalid-model", "\t\t'" + err.property + "' => " + err.message);
			}.bind(this);
			if(log == true) errors.forEach(logerror);
			return false;
		}
		return true;
	},
	
    toJSON: function(){
		return JSON.encode(this.getModel())
    },
  
	toXML  : function(){ 
		return "<" + this.classname.toLowerCase() + ">\n" + json.Json2xml(this.getModel()) + "\n</" + this.classname.toLowerCase() + ">"
	},
	
	get : function(key){
		return this[key];
	},
	
	set : function(key_path, val) {
		this[key_path] = val;
		this.fireEvent("modified", this);
	},
	
	select : function(jsonPath){
		return json.JSONQuery(jsonPath, this.getModel());
	},
	
	asComponentOn : function(aComponent, shouldRender){
		var component = new aComponent(this);
		return component;
	}
});

js.Model.fromJSON = function(string, secure){
    var res = JSON.parse(string);
    var klass = this;
    if (res instanceof Array) {
        var _results = [];
        res.forEach(function(item){
            _results.push(new klass(item));
        });
        return _results;
    }
    else {
        var el = new klass(res);
        return el;
    }
};
